package com.gitee.srurl.system.biz;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.thread.ThreadUtil;
import com.gitee.srurl.core.domain.SusVisitorRecordDomain;
import com.gitee.srurl.core.dto.result.ShortUrlResultDTO;
import com.gitee.srurl.core.service.ISusVisitorRecordService;
import com.gitee.srurl.core.util.ThreadPoolUtil;
import com.gitee.srurl.core.util.Threads;
import com.gitee.srurl.core.util.UniqueIdUtil;
import com.gitee.srurl.core.cache.ShortUrlVisitTimeCache;
import com.gitee.srurl.system.dto.RequestDeviceInfoDTO;
import com.gitee.srurl.system.util.UserAgentUtil;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Optional;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author zxw
 * @date 2023/4/29 21:33
 */
@Slf4j
@Component
public class ShortUrlRedirectBiz {

    private final OpenApiBiz openApiBiz;

    private final ISusVisitorRecordService visitorRecordService;

    /**
     * 消费队列数据
     */
    private volatile boolean consumerQueueRecord = true;

    public ShortUrlRedirectBiz(OpenApiBiz openApiBiz, ISusVisitorRecordService visitorRecordService) {
        this.openApiBiz = openApiBiz;
        this.visitorRecordService = visitorRecordService;
    }

    private final Queue<SusVisitorRecordDomain> visitQueue = new ConcurrentLinkedQueue<>();

    private static final ExecutorService executor = Executors.newSingleThreadScheduledExecutor(runnable -> {
        Thread thread = new Thread(runnable, "visit-queue-consumer");
        thread.setDaemon(false);
        return thread;
    });

    @PostConstruct
    private void init() {
        executor.execute(this::visitQueueConsumerTask);
    }

    @PreDestroy
    private void destroy() {
        this.consumerQueueRecord = false;
        Threads.shutdownAndAwaitTermination(executor);
    }

    /**
     * 如果存在获取短网址对应信息去重定向
     *
     * @param shortId 短链ID
     * @return
     */
    public String getShortUrlRedirectIfEffectivity(String shortId) {

        ShortUrlResultDTO shortUrlResultDTO = openApiBiz.peggingOriginUrlByShortId(shortId);
        if (shortUrlResultDTO == null) {
            return null;
        }

        if (shortUrlResultDTO.getDisabled()) {
            return null;
        }

        LocalDateTime expireTime = shortUrlResultDTO.getExpireTime();
        // 虽然目前设置的是默认半年过期 但是如果今后有需要设置永不过期 这边可能返回null
        if (expireTime!= null && expireTime.isBefore(LocalDateTime.now())) {
            // 说明到了过期时间
            return null;
        }

        long remainTimes = Optional.ofNullable(shortUrlResultDTO.getRemainTimes()).orElse(0L);
        if (remainTimes == -1) {
//            shortUrlResultDTO.setRemainTimes(-1L);
            this.addVisitRecord(shortUrlResultDTO, shortId, true);
            return shortUrlResultDTO.getOriginUrl();
        } else if (remainTimes == 0 || remainTimes < -1) {
            return null;
        } else {
//            shortUrlResultDTO.setRemainTimes(remainTimes);
            this.addVisitRecord(shortUrlResultDTO, shortId, false);
            // 剩余次数 如果小于0 说明超了 设置为0 否则次数减1
//            shortUrlResultDTO.setRemainTimes(remainTimes - 1);
            return shortUrlResultDTO.getOriginUrl();
        }
    }

    /**
     * 添加访问记录
     *
     * @param shortId  短链ID
     * @param infinite 是否为无限次数访问链接
     */
    private void addVisitRecord(ShortUrlResultDTO shortUrlResultDTO,
                                String shortId,
                                boolean infinite) {
        // 获取访问者信息
        RequestDeviceInfoDTO requestDeviceInfo = UserAgentUtil.getRequestDeviceInfo();
        SusVisitorRecordDomain recordDomain = SusVisitorRecordDomain.builder()
                .id(UniqueIdUtil.nextId())
                .shortId(shortId)
                .originUrl(shortUrlResultDTO.getOriginUrl())
                .shortUrl(shortUrlResultDTO.getShortUrl())
                .visitTime(LocalDateTime.now())
                .os(requestDeviceInfo.getOs())
                .browser(requestDeviceInfo.getBrowser())
                .ip(requestDeviceInfo.getIp())
                .build();

        if (!infinite) {
            // 非无限访问次数的话 访问次数-1
            ShortUrlVisitTimeCache.decrementAndGet(shortId);
        }
        visitQueue.offer(recordDomain);
    }

    private void visitQueueConsumerTask() {

        while (this.consumerQueueRecord) {
            SusVisitorRecordDomain visitorRecordDomain = null;
            try {
                visitorRecordDomain = visitQueue.poll();
                if (visitorRecordDomain != null) {
                    SusVisitorRecordDomain t = visitorRecordDomain;
                    // 使用线程池保存
                    ThreadPoolUtil.submit(() -> {
                        log.debug("保存消息:{}", t.getShortId());
                        visitorRecordService.save(t);
                    });
                } else {
                    ThreadUtil.safeSleep(50);
                }
            } catch (Exception e) {
                log.error("数据:{},消费失败:", visitorRecordDomain, e);
            }
        }
        log.info("停止消费队列数据");
    }

//    private class RecordQueueConsumerTask implements Runnable {
//
//        @Override
//        public void run() {
//            while (true) {
//                ShortUrlResultDTO shortUrlResultDTO = null;
//                try {
//                    shortUrlResultDTO = recordQueue.poll();
//                    if (shortUrlResultDTO != null) {
//                        // 使用线程池保存
//                        ThreadPoolUtil.submit(() -> {
//                            // 保存到redis上 然后redis定时刷入 这个不用每次都写到db上
//                        });
//                    } else {
//                        ThreadUtil.safeSleep(50);
//                    }
//                } catch (Exception e) {
//                    log.error("数据:{},消费失败:", shortUrlResultDTO, e);
//                }
//            }
//        }
//    }
}
